//
// Created by none98 on 2021/9/16.
//
#include <GameServer.h>
#include <Context.h>
#include <spdlog/spdlog.h>
#include "LoginService.h"
#include "Login.pb.h"

void LoginService::Serve(TcpConnectionPtr conn, std::string message) {
    LoginRequest req;
    LoginResponse res;
    std::string response;
    req.ParseFromString(message);

    Context* context = static_cast<Context*>(conn->GetContext());
    //handle mysql
    auto sqlConn = context->GetDbConnection();
    //set loginRes
    try{
        std::string sql = "SELECT * FROM game_user where username=?";
        std::unique_ptr<sql::PreparedStatement> statement(sqlConn->prepareStatement(sql));
        statement->setString(1,req.username());
        std::unique_ptr<sql::ResultSet> results(statement->executeQuery());
        if(results->next()==false){ //user dont existed
            spdlog::info("dont have user:{}",req.username());
            res.set_status(GameServer::StatusCode::authFailed);
        }else{//user existed
            if(results->getString("password") != req.userpassword()){// wrong password
                spdlog::info("authority failed user:{}",req.username());
                res.set_status(GameServer::StatusCode::authFailed);
            }else{//right password
                long uid = results->getInt64("uid");
                bool created = results->getBoolean("created");
                context->SetCreated(created);
                context->SetUid(uid);
                res.set_token(uid);
                res.set_status(GameServer::StatusCode::success);
                res.set_rolecreated(created);
                spdlog::info("user:{} login success!",req.username());
                if(created){
                    std::string sql1 = "SELECT * FROM game_user_role where uid=?";
                    std::unique_ptr<sql::PreparedStatement> statement1(sqlConn->prepareStatement(sql1) );
                    statement1->setInt64(1,context->GetUid());
                    std::unique_ptr<sql::ResultSet> resultSet(statement1->executeQuery());
                    while(resultSet->next()){
                        res.add_rolenames(resultSet->getString("rolename"));
                    }
                }
                context->Register(uid,conn);
            }
            conn->AddTimer(0,2,0,0,std::bind(&LoginService::SynData,this,conn),true);
        }
    }catch(sql::SQLException &e){
        spdlog::error("user:{},{}",req.username(), e.what());
        res.set_status(GameServer::StatusCode::failed);
    }
    context->CloseDbConnection(sqlConn);
    //response
    std::string proto = std::move(res.SerializeAsString());
    int length = htonl(8+proto.size());
    int type = htonl(GameServer::ProtoType::loginRes);
    response.append(reinterpret_cast<char*>(&length),4);
    response.append(reinterpret_cast<char*>(&type),4);
    response.append(proto);
    conn->Send(response);
}


void LoginService::SynData(TcpConnectionPtr conn) {
    Context* context = static_cast<Context*>(conn->GetContext());
    spdlog::info("uid:{} stored the role data",context->GetUid());
    context->SumbitTask(std::bind(&Context::Synchronize,context));
}